﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using JsonConverter = System.Text.Json.Serialization.JsonConverter;
using JsonSerializer = System.Text.Json.JsonSerializer;

#endregion

namespace Neto.Json;

/// <summary>
///     System.Text.Json 扩展
/// </summary>
public static class TextJsonExtension
{
    /// <summary>
    ///     获取  System.Text.Json 默认设置
    /// </summary>
    /// <returns></returns>
    public static JsonSerializerOptions GetSerializerOption(bool isLongToString = false, bool initialLowercase = false)
    {
        var options = new JsonSerializerOptions
        {
            //Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),//设置虚拟化中文的时候不编码
            //ReferenceHandler = ReferenceHandler.IgnoreCycles

            // Converters.AddLongTypeConverters();//long类型转换为字符串
            // 设置时间输出统一格式化
            //Converters.AddDateTimeTypeConverters("yyyy-MM-dd HH:mm:ss"),
            //options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Creat(System.Text.Unicode.UnicodeRanges.All);
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, //处理乱码问题
            PropertyNameCaseInsensitive = true, //不区分大小写
            PropertyNamingPolicy = null, //序列化属性名大写（属性原样输出）
            ReferenceHandler = ReferenceHandler.IgnoreCycles, //忽略循环引用
            IncludeFields = true, //包含成员字段序列化
            AllowTrailingCommas = true, //允许尾随逗号
            ReadCommentHandling = JsonCommentHandling.Skip, //允许注释
            NumberHandling = JsonNumberHandling.AllowReadingFromString
        };
        if (isLongToString) options.Converters.AddLongTypeConverters(); //long类型转换为字符串

        //设置为首字母小写
        options.PropertyNamingPolicy = initialLowercase
            ? JsonNamingPolicy.CamelCase
            : //序列化属性名大写（属性原样输出）
            null; //序列化属性名大写（属性原样输出）

        options.Converters.AddDateTimeConverters("yyyy-MM-dd HH:mm:ss"); // 设置时间输出统一格式化
        return options;
    }

    /// <summary>
    ///     获取  System.Text.Json 默认设置
    /// </summary>
    /// <returns></returns>
    public static JsonSerializerOptions GetDeserializeOption()
    {
        var options = new JsonSerializerOptions
        {
            //Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),//设置虚拟化中文的时候不编码
            //ReferenceHandler = ReferenceHandler.IgnoreCycles

            // Converters.AddLongTypeConverters();//long类型转换为字符串
            // 设置时间输出统一格式化
            //Converters.AddDateTimeTypeConverters("yyyy-MM-dd HH:mm:ss"),
            //options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Creat(System.Text.Unicode.UnicodeRanges.All);
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, //处理乱码问题
            PropertyNameCaseInsensitive = true, //不区分大小写
            //PropertyNamingPolicy = null, //序列化属性名大写（属性原样输出）
            ReferenceHandler = ReferenceHandler.IgnoreCycles, //忽略循环引用
            IncludeFields = true, //包含成员字段序列化
            AllowTrailingCommas = true, //允许尾随逗号
            ReadCommentHandling = JsonCommentHandling.Skip, //允许注释
            NumberHandling = JsonNumberHandling.AllowReadingFromString //可允许在反序列化的时候原本应为数字的字符串（带引号的数字）转为数字
        };

        options.Converters.AddDateTimeConverters("yyyy-MM-dd HH:mm:ss"); // 设置时间输出统一格式化
        return options;
    }

    /// <summary>
    ///     序列化为Json字符串（System.Text.Json）
    /// </summary>
    /// <typeparam name="T">对象</typeparam>
    /// <param name="obj">序列化的对象</param>
    /// <param name="option"></param>
    /// <returns></returns>
    public static string ToJson<T>(this T obj, JsonSerializerOptions option = null)
    {
        try
        {
            if (option == null) option = GetSerializerOption();
            var result = JsonSerializer.Serialize(obj, option);
            return result;
        }
        catch (Exception ex)
        {
            LogX.Error($"type:{typeof(T).FullName}\r\n{ex.ToStringEx()}", "Sys\\Error");
            return "";
        }
    }

    /// <summary>
    ///     反序列化为对象（System.Text.Json）
    /// </summary>
    /// <typeparam name="T">对象</typeparam>
    /// <param name="jsonStr">json字符串</param>
    /// <param name="option"></param>
    /// <returns></returns>
    public static T? ToObj<T>(this string jsonStr, JsonSerializerOptions option = null)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(jsonStr)) return default;
            if (option == null) option = GetDeserializeOption();
            return JsonSerializer.Deserialize<T>(jsonStr, option);
        }
        catch (Exception ex)
        {
            LogX.Error($"str:{jsonStr}\r\ntype:{typeof(T).FullName}\r\n{ex.ToStringEx()}", "Sys\\Error");
            return default;
        }
    }

    /// <summary>
    ///     设置text.json mvc选项配置
    /// </summary>
    /// <param name="builder"></param>
    /// <param name="isLongToString"></param>
    /// <param name="initialLowercase">首字母小写，默认false</param>
    /// <returns></returns>
    public static IMvcBuilder AddAbcJsonOptions(this IMvcBuilder builder, bool isLongToString = false,
        bool initialLowercase = false)
    {
        builder.AddJsonOptions(options =>
        {
            if (isLongToString) options.JsonSerializerOptions.Converters.AddLongTypeConverters(); //long类型转换为字符串
            //
            //设置为首字母小写
            options.JsonSerializerOptions.PropertyNamingPolicy = initialLowercase
                ? JsonNamingPolicy.CamelCase
                : //序列化属性名大写（属性原样输出）
                null; //序列化属性名大写（属性原样输出）

            options.JsonSerializerOptions.Converters.AddDateTimeConverters("yyyy-MM-dd HH:mm:ss"); // 设置时间输出统一格式化
            //options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Creat(System.Text.Unicode.UnicodeRanges.All);
            options.JsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; //处理乱码问题
            options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; //不区分大小写

            options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; //忽略循环引用
            options.JsonSerializerOptions.IncludeFields = true; //包含成员字段序列化
            options.JsonSerializerOptions.AllowTrailingCommas = true; //允许尾随逗号
            options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip; //允许注释
            options.JsonSerializerOptions.NumberHandling =
                JsonNumberHandling.AllowReadingFromString; //可允许在反序列化的时候原本应为数字的字符串（带引号的数字）转为数字
        });

        return builder;
    }

    /// <summary>
    ///     添加 DateTime/DateTime?/DateTimeOffset/DateTimeOffset? 类型序列化处理
    /// </summary>
    /// <param name="converters"></param>
    /// <param name="outputFormat"></param>
    /// <returns></returns>
    public static IList<JsonConverter> AddDateTimeConverters(this IList<JsonConverter> converters,
        string outputFormat = default)
    {
        converters.Add(new SystemTextJsonDateTimeConverter(outputFormat));
        converters.Add(new SystemTextJsonNullableDateTimeConverter(outputFormat));

        converters.Add(new SystemTextJsonDateTimeOffsetConverter(outputFormat));
        converters.Add(new SystemTextJsonNullableDateTimeOffsetConverter(outputFormat));

        return converters;
    }


    public static string JsonStringFormatBeautify(this string str)
    {
        var formatJson = JsonSerializer.Serialize(str, new JsonSerializerOptions
        {
            // 整齐打印
            WriteIndented = true,
            //重新编码，解决中文乱码问题
            Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
        });
        return formatJson;
    }
}